<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        margin: 0;
      }
      .div0 {
        width: 200px;
        height: 200px;
        perspective: 700px;
        display: flex;
      }
      .div1 {
        width: 100px;
        height: 100px;
        background-color: red;
        /* transform: skew(45deg); */
        /* transform: skewY(45deg); */
        transform: rotateY(45deg);
      }
      .clear::after {
        content: "";
        height: 0;
        display: block;
        opacity: 0;
        visibility: hidden;
        overflow: hidden;
        clear: both;
      }

      .div2 {
        margin-top: 50px;
        width: 100px;
        height: 100px;
        background-color: red;
      }
      .div3 {
        margin-top: 10px;
        width: 50px;
        height: 50px;
        background-color: orange;
      }
      .div4 {
        width: 100px;
        height: 100px;
        background-color: red;
      }
    </style>
    <!-- 同步加载 加载完并执行完成才会向下一个标签执行 -->
    <!-- <script src="./node_modules/lodash/lodash.js"></script> -->
    <!-- 异步并行 async加载在加载完成后会执行一般等待DOM树渲染完成执行 不会阻碍后续标签的执行 -->
    <!-- <script src="./node_modules/lodash/lodash.js" async></script> -->
    <!-- 异步并行 不会阻碍后续标签的执行，在DOM渲染完成后所有load加载完成之前执行 -->
    <!-- <script src="./node_modules/lodash/lodash.js" defer></script> -->

    <script src="./js/a.js" async></script>
    <script src="./js/b.js" defer></script>
    <script type="module">
      // 所有代码会自动严格模式
      // module中的代码会在DOM属性渲染完成后再会执行
      // console.log("b");
      // function clickHandler() {
      //   console.log("aaa");
      // }
    </script>
    <script>
      // console.log("a");

    </script>
  </head>
  <body>
    <button onclick="clickHandler()">按钮</button>
    <!-- <div class="div0">
        <div class="div1"></div>
    </div> -->

    <!-- <div class="div2">
        <div class="div3"></div>
    </div> -->
    <!-- <div class="div4">
        <p></p>
    </div> -->

    <div></div>
    <script>
      "use strict";

      //   function clickHandler(){
      //     console.log("aaa")
      //   }
      //基础数据类型 number string boolean undefined null symbol
      //引用数据类型 object

      // 当使用typeof判断js中的数据类型时
      // number string boolean undefined symbol object function bigint
      // 139804651110557112n+1n

      // let a=139804651110557112n;
      // console.log(typeof a==="bigint")
      // let a = Symbol()
      // let b = Symbol()
      // console.log(a, b)
      // let a;
      // let b=undefined;
      // console.log(a===b)
      // console.log(typeof a)
      // console.log(typeof b)

      // let c=a;
      // let b=undefined;
      // let a=b=3;
      // console.log(a,b)

      // let arr=[,undefined,1];
      // console.log(arr[0]===arr[1])
      // arr.forEach(item=>{
      //     console.log(item)
      // })
      // var obj={a:1,b:2,c:3};
      // console.log("a" in obj)

      // for(let i=0;i<arr.length;i++){
      //     if(!(i in arr)) continue;
      //     console.log(arr[i])
      // }

      // var o1={a:1,b:2};
      // var o2=Object.create(o1);
      // o2.c=3;
      // console.log(o2.__proto__===o1)
      // console.log(o1.isPrototypeOf(o2))//判断o1是不是o2原型链中的一环

      // var arr=[1,2,3];
      // console.log(arr.__proto__)
      // console.log(Array.prototype)
      // console.log(Array.prototype.isPrototypeOf(arr))

      // var div=document.querySelector("div");
      //    console.log( HTMLDivElement.prototype.isPrototypeOf(div))
      //    console.log( HTMLElement.prototype.isPrototypeOf(div))
      //    console.log( Element.prototype.isPrototypeOf(div))
      //    console.log( Node.prototype.isPrototypeOf(div))
      //    console.log( EventTarget.prototype.isPrototypeOf(div))
      //    console.log( Object.prototype.isPrototypeOf(div))
      // console.dir(div)

      // 除了null和undefined以外任何实例化类型都有constructor
      // console.log(div.constructor===HTMLDivElement)
      // var arr=[1,2,3];
      // console.log(arr.constructor===Array)

      // let a=10;
      // console.log(a.constructor===Number)

      // var o={
      //     b(){
      //         console.log("aa")
      //     }
      // }
      // JSON.stringify 只会将属性转换为JSON字符串，方法不会转换

      // console.log(JSON.stringify(o)==="{}")

      // let a=Symbol("a");
      // var o={
      //     [a]:1
      // }
      // console.log(Object.keys(o).length===0);

      // let a=Symbol("a");
      // var o={
      //     [a]:1
      // };
      // Object.defineProperty(o,"a",{
      //     configurable:true,
      // // 含义: 决定该属性值的描述符是否能被修改, 以及该属性是否能从它所属的对象上被删除, 为true时表示可以
      // // 默认值: false
      //     enumerable:false,
      // // 含义: 控制是否可以在可迭代循环遍历中被枚举, 为true时表示可以
      //     writable:true,
      // // 含义: 决定该属性的值是否能够被赋值运算符改变, 为true时表示可以
      //     value:3
      // })
      // console.log(o)
      // console.log(Object.keys(o))

      // Object.getOwnPropertyNames 获取对象的自身所有字符串类型的属性名数组
      // Object.getOwnPropertySymbols 获取对象的自身所有Symbol类型的属性名数组
      // console.log(Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o)).length===0)

      // Reflect.ownKeys获取对象的自身所有属性名数组(包括可迭代和不可迭代的本身属性)(不包括原型链上的)
      // console.log(Reflect.ownKeys(o).length===0)
      // })

      // var o={a:1,b:2};
      // var o1=Object.create(o);
      // o1.c=3;
      // console.log(o1)

      // in 可以判断这个属性是否属于该对象可枚举的的对象属性和原型属性
      // console.log("a" in o1)
      // for(var key in o1){
      //     console.log(key)
      // }

      // var arr=[1,2,3];
      // console.log(arr)

      // console.log(o1.hasOwnProperty("c"))
      // Object.hasOwn 判断对象自身是否有该属性
      // console.dir(Object.hasOwn(o1,"c"))

      // console.log(Reflect.ownKeys(o1).includes("c"))

      // var o=Object.create(null);//没有原型链的空对象 不可以调用对象的原型链方法
      // var o1={};//有原型链的空对象 可以调用Object的所有原型链中的方法，比如toString()
      // console.log(o1,o);

      //     function news(className,...arg){
      //     //    var o={};
      //     //    Object.setPrototypeOf(o,className.prototype)
      //     //    return o;

      //         var o=Object.create(className.prototype);
      //         className.apply(o,arg)
      //         return o
      //     }

      //    var arr=news(Array)
      //    console.log(arr)

      // let i=1;
      // Object.prototype.toString
      // Object.prototype.valueOf
      // console.log(i==2)

      // Object.prototype.toString=function(){
      //     console.log("o---aaa")
      //     return "a";
      // }

      // Object.prototype.valueOf=function(){
      //     console.log("o---bbb")
      //     return "a"
      // }
      // // var o={a:1};
      // // console.log(o=="a")

      // Number.prototype.toString=function(){
      //     console.log("aaa")
      //     return "1";
      // }
      // Number.prototype.valueOf=function(){
      //     console.log("bbb")
      //     return 2;
      // }
      // let b=new Number(1);
      // console.log(b==2)

      // var o={a:1};
      // Object.prototype.valueOf=function(){
      //     return ++o.a;
      // }
      // console.log(o==2);//true
      // console.log(o==3);//true
      // console.log(o==4);//true

      // let a=1;
      // let b="1";
      // console.log(Object.is(a,b))//与===相似

      // let a="a";
      // console.log(Number(a)===NaN)//===判断任何内容都不等于NaN
      // console.log(Object.is(Number(a),NaN))//Object.is可以判断任何值是否等于NaN

      // let a="a";
      // console.log(isNaN(a))
      // Number.isNaN()  isNaN() 两个的区别
      // console.log(isNaN(a))//isNaN 会隐式转换为数值后判断是否是NaN
      // console.log(Number.isNaN(a));//只判断值是不是NaN，不会隐式转换

      // document.addEventListener("click",clickHandler,bool/option);
      // document.addEventListener("click",clickHandler,true);//true捕获阶段触发
      //   document.addEventListener("click", clickHandler, {
      //     capture: true,
      //     once: true,
      //   }); //capture捕获阶段触发,once只侦听一次销毁
      //   function clickHandler(e) {}

      // e.currentTarget e.target

      // var obj={
      //     a:1,
      //     b(){
      //         this.c()
      //     },
      //     c(){
      //         console.log(this)
      //     }
      // }
      // obj.b()

      //  var obj={
      //     a:1,
      //     b(f){
      //        f()
      //     },
      //     c(){
      //         console.log(this)//严格模式undefined，非严格模式window
      //     }
      // }
      // obj.b(obj.c)

      //   var obj={
      //     a:1,
      //     b(f){
      //        arguments[0]()
      //     },
      //     c(){
      //         console.log(this)//arguments b函数中
      //     }
      // }
      // obj.b(obj.c)

      //  var obj={
      //     a:1,
      //     b(){
      //          console.log(this)//obj
      //          function fn(){
      //             console.log(this)//严格模式undefined，非严格模式window
      //          }
      //          fn()
      //     },

      // }
      // obj.b()

      // setTimeout(function(){
      //     console.log(this)//window
      // })

      // map forEach some every filter find findLast findIndex findLastIndex flatMap
      // 第二个参数会改变函数中this的指向
      // var arr=[1,2,3];
      // arr.forEach(function(){
      //     console.log(this)
      // },arr)

      // var a=1;
      // var obj={
      //     a:2,
      //     b:this.a //?? this不管是否严格模式，指向当前对象外的this指向
      // }
      // console.log(obj)

      // var a=2;
      // class Box{
      //     static a=3;
      //     a=1;
      //     b=this.a//类中实例化属性和方法this指向当前实例化对象
      //     static b=this.a;//使用static定义属性，指向当前类的静态属性和方法
      // }

      // var c=new Box();
      // console.log(c.b)
      // console.log(Box.b)

      // var a=1;
      // var b=new Number(1)
      // console.log(a)
      // console.log(b)

      // function fn(){
      //     console.log(this)
      // }
      // fn.call({a:1})
      // fn.call(1);//当传入替代的值是number，string，boolean，则严格模式时，传入什么this就是什么，非严格模式时这类型会被转换为对应的引用类型

      // 当传入替代的值是null或者undefined时，严格模式时，传入什么，this执行什么，非严格模式时，指向window
      // fn.call(null)
      // fn.call(undefined)

      // 事件侦听回调函数 e.currentTarget
      // 箭头函数中this指向箭头函数外上下文环境中this
      // let o = {
      //   a: 1,
      //   b: 2,
      //   c: {
      //     d: 3,
      //     e: {
      //       f: 4,
      //       g() {},
      //     },
      //   },
      // };
      // 不能复制不可枚举属性，函数并没有复制，而是直接引用
      //   let o1= _.cloneDeep(o)
      //   console.log(o.c.e.g===o1.c.e.g)

      // function cloneDeep(source, isProto = false) {
      //   var target;
      //   switch (true) {
      //     case source instanceof Function:
      //       var arr = source
      //         .toString()
      //         .replace(/\n/g, "")
      //         .match(/^.*?\((.*?)\)\s*\{(.*)\}/)
      //         .slice(1);
      //       target = new Function(...arr);
      //       break;
      //     case source instanceof HTMLElement:
      //       target = source.cloneNode(true);
      //       break;
      //     case source.buffer && source.buffer instanceof ArrayBuffer:
      //     case source instanceof Date:
      //     case source instanceof RegExp:
      //     case source instanceof Set:
      //     case source instanceof Map:
      //       target = new source.constructor(source);
      //       break;
      //     case isProto:
      //       target = {};
      //       break;
      //     default:
      //       target = new source.constructor();
      //   }
      //   var names = Reflect.ownKeys(source);
      //   for (var i = 0; i < names.length; i++) {
      //     var desc = Object.getOwnPropertyDescriptor(source, names[i]);
      //     if (
      //       (desc.value && typeof desc.value === "object") ||
      //       typeof desc.value === "function"
      //     ) {
      //       if (names[i] === "prototype") {
      //         Object.defineProperty(desc.value, "constructor", {
      //           value: target,
      //         });
      //       }
      //       if (names[i] === "constructor") {
      //         continue;
      //       }
      //       Object.defineProperty(target, names[i], {
      //         enumerable: desc.enumerable,
      //         configurable: desc.configurable,
      //         writable: desc.writable,
      //         value:
      //           names[i] === "prototype"
      //             ? cloneDeep(desc.value, true)
      //             : cloneDeep(desc.value),
      //       });
      //     } else {
      //       Object.defineProperty(target, names[i], desc);
      //     }
      //   }
      //   return target;
      // }

      // 响应头设置cors
      // 代理(自己写一个服务代理或者vite，webpack配置代理服务，正式上线使用nginx配置代理)
      // jsonp
      // WebSocket



      //  Object.defineProperty(Function.prototype, "extend", {
      //   value(superClass) {
      //       // this 当前类
      //       // superClass 要继承的超类 父类
      //       // Object.setPrototypeOf(this.prototype,superClass.prototype);
      //       const proto=this.prototype;
      //       this.prototype=Object.create(superClass.prototype);
      //       const keys=Object.getOwnPropertyNames(proto).concat(Object.getOwnPropertySymbols(proto));
      //       for(var i=0;i<keys.length;i++){
      //           var desc=Object.getOwnPropertyDescriptor(proto,keys[i]);
      //           Object.defineProperty(this.prototype,keys[i],desc);
      //       }
      //       Object.defineProperty(Object.prototype,"super",{
      //           value(){
      //              superClass.apply(this,arguments);
      //           }
      //       })
      //       // Object.defineProperty(this.prototype,"superProto",{
      //       //     value:superClass.prototype
      //       // })
      //       // 将父类的静态方法和静态属性也继承到当前对象
      //        Object.setPrototypeOf(this,superClass);
      //   },
      // });

      // function Box1(a, b) {
      //   this.num = 1;
      //   this.a = a;
      //   this.b = b;
      // }
      // Object.defineProperties(Box1.prototype, {
      //   play: {
      //     value() {
      //       console.log(this.a + " play");
      //     },
      //   },
      // });
      // Box1.len = 0;
      // Object.defineProperties(Box1, {
      //   run: {
      //     value() {
      //       console.log("run");
      //     },
      //   },
      // });

      // function Ball1(a,b,c){
      //    this.super(a,b);
      //    this.c=c;
      // }
      // Object.defineProperties(Ball1.prototype,{
      //   play:{
      //       value(){
      //           // this.superProto.play.call(this);
      //           // 当前对象的原型链的上一次原型链中play，也就是父类的原型链方法
      //           Object.getPrototypeOf(Object.getPrototypeOf(this)).play.call(this);
      //           console.log("repeat play");
      //       }
      //   }
      // })

      // Ball1.extend(Box1);



    </script>
    <script>
      console.log("c");
    </script>
  </body>
</html>
<script>
  console.log("d");
</script>
